#include "Jeu.h"


//fonction d'initialisation et de libération

/* Remarque: on passe l'adresse des éléments du jeu. Par exemple pour les fusees, on accede a la structure par "j->fuseeHaut",
puis on donne l'adresse de cette structure: "&(j->fuseeHaut)" */
void initJeu (Jeu *j)
{
    j->nomJoueur1=NULL;
    j->nomJoueur2=NULL;
    j->decisionIA=0;

    initFusee (&(j->fuseeBas));
    initFusee (&(j->fuseeHaut));
    initEquipement(&(j->equipementBas));
    initEquipement(&(j->equipementHaut));
    initTerrain (&(j->terrain));
    initBonus(&(j->bonusVie));

}

void parametreJeu (Jeu *j)
{
    //Entrer ici la taille et la position des differents elements
    int dimXFuseeHaut= 80;
    int dimYFuseeHaut= 135 ;
    int posXFuseeHaut= 100 ;
    int posYFuseeHaut= 10;

    int dimXFuseeBas= 80 ;
    int dimYFuseeBas= 166 ;
    int posXFuseeBas= 500;
    int posYFuseeBas= 420;

    int dimXTerrain= 800;       //Les dimensions du terrain sont aussi celles de l'ecran
    int dimYTerrain= 600;


    //fuseeHaut pour le joueur1
    parametreFusee (&(j->fuseeHaut),1,10,"Florent",dimXFuseeHaut,dimYFuseeHaut,posXFuseeHaut,posYFuseeHaut,100);

    //fuseeBas pour le joueur2

    parametreFusee (&(j->fuseeBas),2, 20, "Houley",dimXFuseeBas,dimYFuseeBas,posXFuseeBas,posYFuseeBas,100);

    //equipements pour le joueur 1
    parametreEquipement (&(j->equipementHaut), 10, 20, 50, 0, 0, 5, 0);

    //equipements pour le joueur 2
    parametreEquipement (&(j->equipementBas), 20, 20, 50, 0,0, 5, 0);

    //terrain de jeu
    parametreTerrain (&(j->terrain), dimXTerrain, dimYTerrain);

    //Bonus Vie
    parametreBonus(&(j->bonusVie),0,100,25,25,0,260);

    //Decision de l'IA
    j->decisionIA=00;

}

void parametreNomJoueurs (Jeu *j)
{

    int taille;
    char chaine[100];

    printf("Entrez un nom pour le joueur 1 : ");
    scanf("%s",chaine);
    taille = strlen(chaine);
    setnomJoueur1(j,chaine,taille);

    //Bonus cache
    if (strcmp (chaine, "Florent")== 0)
    {
        printf("\nBonjourrrr maitre!\n");
    }

    if (strcmp (chaine, "Houley")== 0)
    {
        printf("\nBonjourrrr maitresse!\n");
    }


    printf("\nEntrez un nom pour le joueur 2 : ");
    scanf("%s",chaine);
    taille = strlen(chaine);
    setnomJoueur2(j,chaine,taille);

    //Bonus cache
    if (strcmp (chaine, "Florent")== 0)
    {
        printf("\nBonjourrrr maitre!\n");
    }

    if (strcmp (chaine, "Houley")== 0)
    {
        printf("\nBonjourrrr maitresse!\n");
    }

}

void libereJeu (Jeu *j)
{
    assert(j!=NULL);
    free(j->nomJoueur1);
    free(j->nomJoueur2);
    libereFusee(&(j->fuseeHaut));
    libereFusee(&(j->fuseeBas));
    libereTerrain(&(j->terrain));
}


//accesseurs
char* getnomJoueur1(const Jeu *j)
{
    assert(j!=NULL);
    return ( j->nomJoueur1);
}
char* getnomJoueur2(const Jeu *j)
{
    assert(j!=NULL);
    return (j->nomJoueur2);
}
Fusee* getFuseeHaut(Jeu *j)
{
    assert(j!=NULL);
    return &(j->fuseeHaut);
}
Fusee* getFuseeBas(Jeu *j)
{
    assert(j!=NULL);
    return &(j->fuseeBas);
}
Equipement* getEquipementHaut(Jeu *j)
{
    assert(j!=NULL);
    return &(j->equipementHaut);
}
Equipement* getEquipementBas(Jeu *j)
{
    assert(j!=NULL);
    return &(j->equipementBas);
}
Terrain* getTerrain(Jeu *j)
{
    assert(j!=NULL);
    return &(j->terrain);
}

Bonus* getBonusVie (Jeu *j)
{
    assert (j!=NULL);
    return &(j->bonusVie);
}

int getDecisionIA(Jeu *j)
{
    assert(j!=NULL);
    return j->decisionIA;
}

//mutateurs

/* Pour les chaines de caracteres nomJoueur, on utilise un pointeur sur caractere.
Pour la remplir, on alloue une chaine dans le tas, et le pointeur nomJoueur contiendra l'adresse de la chaine */

/*atention: il faut connaitre la taille des chaines qu'on met dans la structure! */

void setnomJoueur1(Jeu *j,const char *nomJoueur1, int taille)
{
    assert(j!=NULL);
    j->nomJoueur1= malloc(sizeof(char)*(taille+1));
    strcpy(j->nomJoueur1,nomJoueur1);

}
void setnomJoueur2(Jeu *j, const char *nomJoueur2, int taille)
{
    assert(j!=NULL);
    j->nomJoueur2= malloc(sizeof(char)*(taille+1));
    strcpy(j->nomJoueur2,nomJoueur2);
}

void setDecisionIA(Jeu *j, int decision)
{
    assert(j!=NULL);
    j->decisionIA=decision;
}


//fonctions de Jeu
void actionsClavier (Jeu *j, const char touche)
{
    switch (touche)
    {
    case 'l':                                   //touches pour la fusee du bas
        deplacerFuseeGauche(&(j->fuseeBas));          //rq: 'l' designe la fleche de gauche et 'r' la fleche de droite
        break;


    case 'r':
        deplacerFuseeDroite(&(j->fuseeBas));
        break;

    case 'u':
        deplacerFuseeHaut(&(j->fuseeBas));
        break;

    case 'n':
        deplacerFuseeBas(&(j->fuseeBas));
        break;

    case 'p':
        tirFusee(j,&(j->fuseeBas));
        break;

    case 'q':                                    //touches pour la fusee du haut
        deplacerFuseeGauche(&(j->fuseeHaut));
        break;

    case 'd':
        deplacerFuseeDroite(&(j->fuseeHaut));
        break;

    case 'z':                                    //touches pour la fusee du haut
        deplacerFuseeHaut(&(j->fuseeHaut));            // attention: fuseeHaut designe la fusee du haut, et deplacerFuseeHaut la fonction permettant de deplacer une fusee
        break;

    case 's':
        deplacerFuseeBas(&(j->fuseeHaut));
        break;

    case 'c':
        tirFusee(j,&(j->fuseeHaut));
        break;

    }

}

/**
@brief Retourne l'id de la fusee qui a gagne
**/
int finJeu (Jeu *j)
{
    if (getpointVieFusee(getFuseeHaut(j))<=0)   //Si la Fusee du haut a perdu
    {
        return 2;
    }
    else
    {
        if((getpointVieFusee(getFuseeBas(j))<=0))  //Si la Fusee du bas a perdu
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}



//Gestion des fusees et des tirs
/**
@brief Fonction permettant de creer un tir (un Equipement) à partir de la fusee
**/

void tirFusee (Jeu *j, Fusee *f)
{
    if (getidEquipementFusee(f)==10)   //Equipement normal de la fuseeHaut
    {
        ajouterEquipementTerrainEnParametrant(getTerrain(j),10, 20, 20, posXmoyenneFusee(f) , getposYFusee(f)+getdimYFusee(f), 1, 0);
    }
    if (getidEquipementFusee(f)==20)   //Equipement normal de la fuseeHaut
    {
        ajouterEquipementTerrainEnParametrant(getTerrain(j),20, 20, 70, posXmoyenneFusee(f) , getposYFusee(f), 1, 0);
    }
}

/**
@brief Fonction permettant deplacer les equipements
**/
void gestionDeplacementEquipements(Jeu *j)
{

    int i =0;
    Terrain *t;
    TableauDynamique *tab;

    t=getTerrain(j); //t est un pointeur vers le terrain
    tab=getTableauDynamiqueTerrain(t); //tab est un pointeur sur le tableau dynamique du terrain

    if ((getPointeurTableauDynamique(tab)!=NULL))
    {
        for(i=0; i<getTailleTabDyn(tab); i++) //On parcourt tout le tableau dynamique
        {
            deplacerEquipement(getIemeElementTabDyn(&(t->tab),i));    //On deplace l'equipement situe à la case i du tableau dynamique
        }
    }
}

/**
@brief Fonction gerant les collisions entre les tirs
**/
void gestionCollisionEquipements(Jeu *j)
{
    int i = 0;
    int supprime = 0;    //Permet de dire si un equipement a ete supprime et si il faut recommencer la boucle
    int posX;
    int posY;
    Terrain *t;
    Equipement *eq;
    TableauDynamique *tab;
    Fusee *fuseeHaut;
    Fusee *fuseeBas;
    Bonus *b;

    t=getTerrain(j); //t est un pointeur vers le terrain
    tab=getTableauDynamiqueTerrain(t); //tab est un pointeur sur le tableau dynamique du terrain
    fuseeHaut=getFuseeHaut(j);
    fuseeBas=getFuseeBas(j);
    b=getBonusVie(j);

    //Tant qu'on a pas parcourut tout le tableau
    while(i<getTailleTabDyn(tab))
    {
        supprime=0;
        eq=getIemeElementTabDyn(tab,i); //eq est le pointeur vers le ieme equipement du tableau dynamique
        assert(eq!=NULL);

        posX = getposXEquipement(eq);
        posY = getposYEquipement(eq);


        //On teste si l'equipement est en collision
        if ((posY<(-getdimYEquipement(eq)-10)) && (supprime==0))
        {
            supprimerElementTabDyn(tab, i);
            supprime=1;

        }

        if ((posY>getdimYTerrain(t))&&(supprime==0))
        {
            supprimerElementTabDyn(tab, i);
            supprime=1;
        }

        //On teste si l'equipement est en collision avec la fusee du haut

        if ((posX>=(getposXFusee(fuseeHaut))&&(posX<=(getposXFusee(fuseeHaut)+getdimXFusee(fuseeHaut)))&&(posY>=getposYFusee(fuseeHaut))&&(posY<=getposYFusee(fuseeHaut)+getdimYFusee(fuseeHaut)))&& (supprime==0))
        {
           // setpointVieFusee(fuseeHaut,getpointVieFusee(fuseeHaut)-5);
            enleverPointsVie(fuseeHaut,eq);
            supprimerElementTabDyn(tab,i);
            supprime=1;
        }

        //On teste si l'equipement est en collision avec la fusee du bas

        if ((posX>=getposXFusee(fuseeBas))&&(posX<=(getposXFusee(fuseeBas)+getdimXFusee(fuseeBas)))&&(posY>=getposYFusee(fuseeBas))&&(posY<=getposYFusee(fuseeBas)+getdimYFusee(fuseeBas))&& (supprime==0))
        {
            enleverPointsVie (fuseeBas,eq);
            supprimerElementTabDyn( tab, i );
            supprime=1;
        }


        //Gestion des bonus
        if (getvisibiliteBonus(b)==1)
        {
            if ((posX>=(getposXBonus(b)))&&(posX<=(getposXBonus(b)+getdimXBonus(b)))&&(posY>=getposYBonus(b))&&(posY<=getposYBonus(b)+getdimYBonus(b)))
            {
                ajouterPointsVie(j,eq);
                setvisibiliteBonus(b,0); //On rend le bonus invisible
            }
        }

        if (supprime==1)
        {
            i=0; //On reinitialise le compteur
        }
        else
        {
            i++; //On incremente le compteur
        }

    }

}

void ajouterPointsVie(Jeu *j, Equipement *eq)
{
    if(getidEquipement(eq)==10) //Equipement de la fusee du haut
    {
        ajouterPointsVieFusee(getFuseeHaut(j));
    }
    if (getidEquipement(eq)==20) //Equipement de la fusee du bas
    {
        ajouterPointsVieFusee(getFuseeBas(j));
    }
}


//Intelligence Artificielle
/**
@brief Permet à l'IA de changer sa décision actuelle
**/

/*retourne le code de sa decision */
void changementDecisionIA (Jeu *j)
{
    int i;
    int posX;
    int posXFuseeAdverse;
    int aleatoire;
    int decisionPrise;

    Fusee *fuseeHaut;
    Fusee *fuseeBas;  //contrôlée par l'IA
    Equipement *eq;
    TableauDynamique *tab;
    Bonus *b;

    fuseeHaut = getFuseeHaut(j);
    fuseeBas = getFuseeBas(j);
    tab=getTableauDynamiqueTerrain(getTerrain(j));
    b=getBonusVie(j);

    posXFuseeAdverse = getposXFusee(fuseeHaut);
    posX = getposXFusee(fuseeBas);

    aleatoire = rand()%100; //compris entre 0 et 100
    decisionPrise = 0;

    /* ## Prise des bonus ## */
    if((getvisibiliteBonus(b)==1)&&(decisionPrise!=1))
    {
        if(posX<getposXBonus(b)-10)
        {
            setDecisionIA(j,10);
            decisionPrise = 1;
        }
        if (posX>getposXBonus(b)+getdimXBonus(b)+10)
        {
            setDecisionIA(j,-10);
            decisionPrise = 1;
        }
        if ((posX>=getposXBonus(b)-10)&&(posX<=getposXBonus(b)+getdimXBonus(b)+10))
        {
            setDecisionIA(j,00);
            decisionPrise = 1;
        }
    }

    /*## Esquive ## */
    /* On parcourt tout le tableau pour voir si il y a des equipements a esquiver */
    if ((getPointeurTableauDynamique(tab)!=NULL)&&(decisionPrise!=1))
        {
        for(i=0; i<getTailleTabDyn(tab); i++) //On parcourt tout le tableau dynamique
            {
                eq=getIemeElementTabDyn(tab,i);
                    if((getposYEquipement(eq)>=getposYFusee(fuseeBas)-50)&&(getposYEquipement(eq)<=780))
                    /* Si l'equipement est à droite de la fusee */
                    if ((getposXEquipement(eq)>=posXmoyenneFusee(fuseeBas))&&((getposXEquipement(eq))<=posXmoyenneFusee(fuseeBas)+60))
                        {
                            setDecisionIA(j,-10);
                            decisionPrise = 1;
                        }
                    else
                    {   /* Si l'equipement est à gauche de la fusee */
                        if ((getposXEquipement(eq)>=posXmoyenneFusee(fuseeBas)-60)&&((getposXEquipement(eq))<=posXmoyenneFusee(fuseeBas)))
                        {
                            setDecisionIA(j,10);
                            decisionPrise = 1;
                        }
                    }

            }
            }

    /* ## Deplacement ## */
    if (decisionPrise!=1)
    {
        if((posX<posXFuseeAdverse-30)&&(decisionPrise!=1)) //Si la Fusee est à gauche
        {
            if (aleatoire<80) //Cas le plus probable
            {
                setDecisionIA(j,10);//deplacer à droite
                decisionPrise = 1;
            }
            if ((aleatoire>80)&&(aleatoire<90))
            {
                setDecisionIA(j,-10);//déplacer à gauche
                decisionPrise = 1;
            }
            if (aleatoire>90)
            {
                setDecisionIA(j,00);//rester sur place
                decisionPrise = 1;
            }
        }

        if((posX>posXFuseeAdverse+getdimXFusee(fuseeHaut)+30)&&(decisionPrise!=1))  //Si la fusee est à droite
        {
            if (aleatoire<80) //Cas le plus probable
            {
                setDecisionIA(j,-10);
                decisionPrise = 1;
            }
            if ((aleatoire>80)&&(aleatoire<90))
            {
                setDecisionIA(j,10);
                decisionPrise = 1;
            }
            if (aleatoire>90)
            {
                setDecisionIA(j,00);
                decisionPrise = 1;
            }
        }
        if ((posX>=posXFuseeAdverse-30)&&(posX<=posXFuseeAdverse+getdimXFusee(fuseeHaut)+30)&&(decisionPrise!=1))  //Si la fusee est au niveau de l'autre fusee
        {
            if (aleatoire<60) //Cas le plus probable
            {
                setDecisionIA(j,00);
                decisionPrise = 1;
            }
            if ((aleatoire>60)&&(aleatoire<80))
            {
                setDecisionIA(j,10);
                decisionPrise = 1;
            }
            if (aleatoire>80)
            {
                setDecisionIA(j,-10);
                decisionPrise = 1;
            }
        }
    }
}


void tirIA (Jeu *j)
{
    int posX;
    int posXFuseeAdverse;
    int distanceAleatoire;
    int decisionTir;
    int decisionTirSpontannee;

    Fusee *fuseeHaut;
    Fusee *fuseeBas;  //contrôlée par l'IA
    Bonus *b;

    fuseeHaut = getFuseeHaut(j);
    fuseeBas = getFuseeBas(j);
    b = getBonusVie(j);

    posXFuseeAdverse = getposXFusee(fuseeHaut);
    posX = getposXFusee(fuseeBas);

    distanceAleatoire = rand()%20; //nombre aleatoire entre 0 et 20
    decisionTir = rand()%100; //pourcentage de chance de tirer
    decisionTirSpontannee = rand()%100; //pourcentage de chance de tirer sans raison

    /*Tir si on a un bonus */
     if ((posX>=getposXBonus(b)-50)&&(posX<=getposXBonus(b)+getdimXBonus(b)+50))
        {
             tirFusee(j,fuseeBas);
        }

    /* Tir si on es en dessous de la fusee adverse */
    if ((posX>=posXFuseeAdverse-40-distanceAleatoire)&&(posX<=posXFuseeAdverse+getdimXFusee(fuseeHaut)+40+distanceAleatoire))
    {
        if(decisionTir<80)  //L'IA ne tire que dans 80% des cas
        {
            tirFusee(j,fuseeBas);
        }
    }

    /* Tir sans raison */
    if (decisionTirSpontannee>20) //L'IA tire 20% des cas sans raison
    {
        tirFusee(j,fuseeBas);
    }
}


//Test de non-régression
void testRegressionJeu()
{

    printf("###  Test du module jeu ### \n");

    Jeu jeu;

    //test des fonctions d'initialisation
    initJeu (&jeu);
    printf("-- Fonctions d'initialisation testees avec succes -- \n");

    //test des accesseurs et mutateurs
    setnomJoueur1(&jeu, "houley",6);
    setnomJoueur2(&jeu, "florent",7);

    assert ( strcmp( getnomJoueur1(&jeu) ,"houley") ==0);
    assert ( strcmp( getnomJoueur2(&jeu) ,"florent") ==0);

    printf("-- Accesseurs et mutateurs testes avec succes  -- \n");

    //test de la fonction de libération
    libereJeu(&jeu);

    printf("-- Fonction de liberation testee avec succes  -- \n");

    printf("***  Test du module jeu realise avec succes *** \n\n\n");

}


void affichageStructuresJeu (Jeu *j)
{
    printf("\n### nom des joueurs   ###\n");
    printf("\nNom joueur 1: %s",j->nomJoueur1);
    printf("\nNom joueur 2: %s",j->nomJoueur2);

    printf("\n\n");
    printf("### fuseeHaut   ###\n");
    printf("idFusee: %d \n",j->fuseeHaut.idFusee );
    printf("idEquipement: %d \n",j->fuseeHaut.idEquipement );
    printf("nomJoueur: %s\n",j->fuseeHaut.nomJoueur );
    printf("dimX: %d \n",j->fuseeHaut.dimX );
    printf("dimY: %d \n",j->fuseeHaut.dimY );
    printf("posX: %d \n",j->fuseeHaut.posX );
    printf("posY: %d \n",j->fuseeHaut.posY );
    printf("pointvie: %d \n",j->fuseeHaut.pointVie );

}
